home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Atari Compendium
/
The Atari Compendium (Toad Computers) (1994).iso
/
files
/
umich
/
network
/
ka9q
/
nhclb120.zoo
/
nr3.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-06-18
|
26KB
|
983 lines
/* net/rom level 3 low level processing
* Copyright 1989 by Daniel M. Frank, W9NK. Permission granted for
* non-commercial distribution only.
*/
#include <stdio.h>
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "timer.h"
#include "arp.h"
#include "slip.h"
#include "ax25.h"
#include "netrom.h"
#include "nr4.h"
#include "lapb.h"
#include <ctype.h>
#ifdef UNIX
#include <string.h>
#include <memory.h>
#endif
static struct nr_bind *find_best();
/* Nodes message broadcast address: "NODES" in shifted ASCII */
struct ax25_addr nr_nodebc = {
'N'<<1, 'O'<<1, 'D'<<1, 'E'<<1, 'S'<<1, ' '<<1,
('0'<<1) | E
} ;
struct nriface nrifaces[NRNUMIFACE] ;
unsigned nr_numiface ;
struct nrnbr_tab *nrnbr_tab[NRNUMCHAINS] ;
struct nrroute_tab *nrroute_tab[NRNUMCHAINS] ;
struct nrnf_tab *nrnf_tab[NRNUMCHAINS] ;
unsigned nr_nfmode = NRNF_NOFILTER ;
unsigned nr_ttl = 64 ;
unsigned obso_init = 6 ;
unsigned obso_minbc = 5 ;
unsigned nr_maxroutes = 5 ;
unsigned nr_autofloor = 1 ;
unsigned nr_verbose = 0 ;
struct interface *nr_interface ;
/* send a NET/ROM layer 3 datagram */
void nr3output(dest, data)
struct ax25_addr *dest ;
struct mbuf *data ;
{
struct nr3hdr n3hdr ;
struct mbuf *n3b ;
n3hdr.dest = *dest ; /* copy destination field */
n3hdr.ttl = nr_ttl ; /* time to live from initializer parm */
if ((n3b = htonnr3(&n3hdr)) == NULLBUF) {
free_p(data) ;
return ;
}
append(&n3b, data) ;
/* The null interface indicates that the packet needs to have */
/* an appropriate source address inserted by nr_route */
nr_route(n3b,NULLAX25) ;
}
/* send IP datagrams across a net/rom network connection */
/*ARGSUSED*/
int
nr_send(bp,interface,gateway,precedence,delay,throughput,reliability)
struct mbuf *bp ;
struct interface *interface ;
int32 gateway ;
char precedence ;
char delay ;
char throughput ;
char reliability ;
{
struct ax25_addr dest ;
struct mbuf *pbp ;
struct nr4hdr n4hdr ;
char *hwaddr ;
struct arp_tab *arp ;
if ((arp = arp_lookup(ARP_NETROM,gateway)) == NULLARP) {
free_p(bp) ; /* drop the packet if no route */
return ;
}
hwaddr = arp->hw_addr ; /* points to destination */
memcpy(dest.call, hwaddr, ALEN) ;
dest.ssid = hwaddr[ALEN] ;
/* Create a "network extension" transport header */
n4hdr.opcode = NR4OPPID ;
n4hdr.u.pid.family = PID_IP ;
n4hdr.u.pid.proto = PID_IP ;
if ((pbp = htonnr4(&n4hdr)) == NULLBUF) {
free_p(bp) ;
return ;
}
append(&pbp,bp) ; /* Append the data to that */
nr3output(&dest, pbp) ; /* and pass off to level 3 code */
}
/* Figure out if a call is assigned to one of my net/rom
* interfaces.
*/
static int
ismycall(addr)
struct ax25_addr *addr ;
{
register int i ;
int found = 0 ;
for (i = 0 ; i < nr_numiface ; i++)
if (addreq((struct ax25_addr *)(nrifaces[i].interface->hwaddr),
addr)) {
found = 1 ;
break ;
}
return found ;
}
/* Route net/rom network layer packets.
*/
nr_route(bp, iaxp)
struct mbuf *bp ; /* network packet */
struct ax25_cb *iaxp ; /* incoming ax25 control block */
{
struct nr3hdr n3hdr ;
struct nr4hdr n4hdr ;
struct ax25_cb *axp, *find_ax25(), *open_ax25() ;
struct ax25 naxhdr ;
struct ax25_addr neighbor, from ;
struct mbuf *hbp, *pbp ;
extern int16 axwindow ;
void ax_incom(), nr4input() ;
register struct nrnbr_tab *np ;
register struct nrroute_tab *rp ;
register struct nr_bind *bindp ;
struct nr_bind *find_best() ;
struct interface *interface ;
unsigned ifnum ;
if (ntohnr3(&n3hdr,&bp) == -1) {
free_p(bp) ;
return ;
}
/* If this isn't an internally generated network packet,
* give the router a chance to record a route back to the
* sender, in case they aren't in the local node's routing
* table yet.
*/
if (iaxp != NULLAX25) {
/* find the interface number */
for (ifnum = 0 ; ifnum < nr_numiface ; ifnum++)
if (iaxp->interface == nrifaces[ifnum].interface)
break ;
if (ifnum == nr_numiface) { /* shouldn't happen! */
free_p(bp) ;
return ;
}
from = iaxp->addr.dest ;
from.ssid |= E ;
/* Add (possibly) a zero-quality recorded route via */
/* the neighbor from which this packet was received */
/* Note that this doesn't work with digipeated neighbors, */
/* at this point. */
(void) nr_routeadd(" ",&n3hdr.source,ifnum,0,
(char *)&from,0,1) ;
}
/* A packet from me, to me, can only be one thing: */
/* a horrible routing loop. This will probably result */
/* from a bad manual ARP entry, but we should fix these */
/* obscure errors as we find them. */
if (ismycall(&n3hdr.dest)) {
if (iaxp == NULLAX25) { /* From me? */
free_p(bp) ;
return ;
} else { /* It's from somewhere else! */
if (ntohnr4(&n4hdr,&bp) == -1) {
free_p(bp) ;
return ;
}
if ((n4hdr.opcode & NR4OPCODE) == 0) {
if (n4hdr.u.pid.family == PID_IP
&& n4hdr.u.pid.proto == PID_IP)
ip_route(bp,0) ;
else /* we don't do this proto */
free_p(bp) ;
return ;
}
/* Must be net/rom transport: */
nr4input(&n4hdr,bp) ;
}
return ;
}
if ((rp = find_nrroute(&n3hdr.dest)) == NULLNRRTAB) {
/* no route, drop the packet */
free_p(bp) ;
return ;
}
if ((bindp = find_best(rp->routes,1)) == NULLNRBIND) {
/* This shouldn't happen yet, but might if we add */
/* dead route detection */
free_p(bp) ;
return ;
}
np = bindp->via ;
memcpy(neighbor.call,np->call,ALEN) ;
neighbor.ssid = np->call[ALEN] ;
interface = nrifaces[np->interface].interface ;
/* Now check to see if iaxp is null. That is */
/* a signal that the packet originates here, */
/* so we need to insert the callsign of the appropriate */
/* interface */
if (iaxp == NULLAX25)
memcpy((char *)&n3hdr.source,interface->hwaddr,AXALEN) ;
/* Make sure there is a connection to the neighbor */
if ((axp = find_ax25(&neighbor)) == NULLAX25 ||
(axp->state != CONNECTED && axp->state != RECOVERY)) {
/* Open a new connection or reinitialize old one */
/* hwaddr has been advanced to point to neighbor + digis */
atohax25(&naxhdr, np->call, (struct ax25_addr *)interface->hwaddr) ;
axp = open_ax25(&naxhdr, axwindow, ax_incom, NULLVFP, NULLVFP,
interface,(char *)0) ;
if (axp == NULLAX25) {
free_p(bp) ;
return ;
}
}
if (--n3hdr.ttl == 0) { /* the packet's time to live is over! */
free_p(bp) ;
return ;
}
/* allocate and fill PID mbuf */
if ((pbp = alloc_mbuf(1)) == NULLBUF) {
free_p(bp) ;
return ;
}
pbp->cnt = 1 ;
*pbp->data = (PID_FIRST | PID_LAST | PID_NETROM) ;
/* now format network header */
if ((hbp = htonnr3(&n3hdr)) == NULLBUF) {
free_p(pbp) ;
free_p(bp) ;
return ;
}
append(&pbp,hbp) ; /* append header to pid */
append(&pbp,bp) ; /* append data to header */
send_ax25(axp,pbp) ; /* pass it off to ax25 code */
}
/* Perform a nodes broadcast on interface # ifno in the net/rom
* interface table.
*/
nr_bcnodes(ifno)
unsigned ifno ;
{
struct mbuf *hbp, *dbp, *savehdr ;
struct nrroute_tab *rp ;
struct nrnbr_tab *np ;
struct nr_bind * bp ;
struct nr3dest nrdest ;
int i, didsend = 0, numdest = 0 ;
register char *cp ;
struct interface *axif = nrifaces[ifno].interface ;
struct nr_bind *find_best() ;
/* prepare the header */
if ((hbp = alloc_mbuf(NR3NODEHL)) == NULLBUF)
return ;
hbp->cnt = NR3NODEHL ;
*hbp->data = NR3NODESIG ;
memcpy(hbp->data+1,nrifaces[ifno].alias,ALEN) ;
/* Some people don't want to advertise any routes; they
* just want to be a terminal node. In that case we just
* want to send our call and alias and be done with it.
*/
if (!nr_verbose) {
(*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
(PID_FIRST | PID_LAST | PID_NETROM),
hbp) ; /* send it */
return ;
}
/* make a copy of the header in case we need to send more than */
/* one packet */
savehdr = copy_p(hbp,NR3NODEHL) ;
/* now scan through the routing table, finding the best routes */
/* and their neighbors. create destination subpackets and append */
/* them to the header */
for (i = 0 ; i < NRNUMCHAINS ; i++) {
for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
/* look for best, non-obsolescent route */
if ((bp = find_best(rp->r